package com.tang.generate.utils

import com.tang.generate.domain.GenField
import com.tang.generate.model.ConfigVO
import com.tang.generate.model.EnumVO
import com.tang.generate.model.GenVO
import com.tang.generate.model.req.ReqGenerate
import org.apache.velocity.VelocityContext
import org.apache.velocity.app.Velocity
import java.io.ByteArrayOutputStream
import java.io.StringWriter
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream


object VelocityUtils {

    private val templateList = listOf(
        "vm/java/model/req/ReqAdd.java.vm",
        "vm/java/model/req/Req.java.vm",
        "vm/java/model/res/Res.java.vm",
        "vm/java/model/res/ResDetail.java.vm",
        "vm/java/Controller-admin.java.vm",
        "vm/java/Domain.java.vm",
        "vm/java/Facade.java.vm",
        "vm/java/IService.java.vm",
        "vm/java/Mapper.java.vm",
        "vm/java/ServiceImpl.java.vm",
        "vm/react/config/columns.tsx.vm",
        "vm/react/api.ts.vm",
        "vm/react/index.tsx.vm",
        "vm/react/type.ts.vm",
        "vm/react/components/add.tsx.vm",
        "vm/react/components/config/fields.ts.vm"
    )

    private var enumTemplateList = listOf<String>("vm/java/enums/enum.java.vm", "vm/react/enums/enum.ts.vm");


    private val configTemplate = listOf<String>("vm/java/properties/Config.java.vm")

    /**
     * 获取文件名
     */
    private fun getFileName(template: String, genVO: GenVO): String {
        val javaPath = genVO.packageName!!.replace(".", "/")
        var fileName: String = "";
        if (template.contains("Domain.java.vm")) {
            fileName = "${javaPath}/domain/${genVO.clazzName}.java"
        }
        if (template.contains("Mapper.java.vm")) {
            fileName = "${javaPath}/mapper/${genVO.clazzName}Mapper.java"
        } else if (template.contains("IService.java.vm")) {
            fileName = "${javaPath}/service/I${genVO.clazzName}Service.java"
        } else if (template.contains("ServiceImpl.java.vm")) {
            fileName = "${javaPath}/service/impl/${genVO.clazzName}ServiceImpl.java"
        } else if (template.contains("controller.java.vm")) {
            fileName = "${javaPath}/controller/${genVO.clazzName}Controller.java"
        } else if (template.contains("Facade.java.vm")) {
            fileName = "${javaPath}/facade/${genVO.clazzName}Facade.java"
        } else if (template.contains("Req.java.vm")) {
            fileName = "${javaPath}/model/req/Req${genVO.clazzName}.java"
        } else if (template.contains("ReqAdd.java.vm")) {
            fileName = "${javaPath}/model/req/Req${genVO.clazzName}Add.java"
        } else if (template.contains("Res.java.vm")) {
            fileName = "${javaPath}/model/res/Res${genVO.clazzName}TableItem.java"
        } else if (template.contains("ResDetail.java.vm")) {
            fileName = "${javaPath}/model/res/Res${genVO.clazzName}Detail.java"
        } else if (template.contains("Controller-admin.java.vm")) {
            fileName = "${javaPath}/controller/${genVO.clazzName}Controller.java"
        } else if (template.contains("Tag.ts.vm")) {
            fileName = "react/services/${genVO.frontPath}/Tag.ts"
        } else if (template.contains("index.tsx.vm")) {
            fileName = "react/pages/${genVO.frontPath}/list/index.tsx"
        } else if (template.contains("type.ts.vm")) {
            fileName = "react/pages/${genVO.frontPath}/type.ts"
        } else if (template.contains("columns.tsx.vm")) {
            fileName = "react/pages/${genVO.frontPath}/list/config/columns.tsx"
        } else if (template.contains("fields.ts.vm")) {
            fileName = "react/pages/${genVO.frontPath}/list/components/Add${genVO.clazzName}/config/fields.tsx"
        } else if (template.contains("add.tsx.vm")) {
            fileName = "react/pages/${genVO.frontPath}/list/components/Add${genVO.clazzName}/index.tsx"
        }

        return fileName
    }

    fun getFileName(template: String, enumVO: EnumVO, groupId: String): String {
        val javaPath = groupId.replace(".", "/");
        var fileName: String = ""
        if (template.contains("enum.java.vm")) {
            fileName = "${javaPath}/common/enums/${enumVO.clazzName}.java"
        } else if (template.contains("enum.ts.vm")) {
            fileName = "react/src/type/enum/${enumVO.clazzName}.ts"
        }
        return fileName;
    }

    private fun getFileName(template: String, configVO: ConfigVO, groupId: String): String {
        val javaPath = groupId.replace(".", "/");
        var fileName: String = ""
        if (template.contains("Config.java.vm")) {
            fileName = "${javaPath}/common/properties/${configVO.clazzName}.java"
        }
        return fileName;
    }

    private fun getName(template: String, genVO: GenVO): String {
        val javaPath = genVO.packageName!!.replace(".", "/")
        var fileName: String = "";
        if (template.contains("Domain.java.vm")) {
            fileName = "${genVO.clazzName}.java"
        }
        if (template.contains("Mapper.java.vm")) {
            fileName = "${genVO.clazzName}Mapper.java"
        } else if (template.contains("IService.java.vm")) {
            fileName = "I${genVO.clazzName}Service.java"
        } else if (template.contains("ServiceImpl.java.vm")) {
            fileName = "${genVO.clazzName}ServiceImpl.java"
        } else if (template.contains("controller.java.vm")) {
            fileName = "${genVO.clazzName}Controller.java"
        } else if (template.contains("Facade.java.vm")) {
            fileName = "${genVO.clazzName}Facade.java"
        } else if (template.contains("Req.java.vm")) {
            fileName = "Req${genVO.clazzName}.java"
        } else if (template.contains("ReqAdd.java.vm")) {
            fileName = "Req${genVO.clazzName}Add.java"
        } else if (template.contains("Res.java.vm")) {
            fileName = "Res${genVO.clazzName}TableItem.java"
        } else if (template.contains("ResDetail.java.vm")) {
            fileName = "Res${genVO.clazzName}Detail.java"
        } else if (template.contains("Controller-admin.java.vm")) {
            fileName = "${genVO.clazzName}Controller.java"
        } else if (template.contains("api.ts.vm")) {
            fileName = "Tag.ts"
        } else if (template.contains("index.tsx.vm")) {
            fileName = "index.tsx"
        } else if (template.contains("type.ts.vm")) {
            fileName = "type.ts"
        } else if (template.contains("columns.tsx.vm")) {
            fileName = "columns.tsx"
        } else if (template.contains("fields.ts.vm")) {
            fileName = "fields.tsx"
        } else if (template.contains("add.tsx.vm")) {
            fileName = "addModal.tsx"
        }

        return fileName
    }


    fun getZipCode(genVOList: List<GenVO>): ByteArray {
        val byteArrayOutputStream = ByteArrayOutputStream();
        val zipOutputStream = ZipOutputStream(byteArrayOutputStream)
        genVOList.forEach {
            VelocityInitializer.initVelocity()
            val context = VelocityContext()
            GenUtils.processImportList(it);
            templateList.forEach { template ->
                context.put("gen", it)
                val tlt = Velocity.getTemplate(template, "utf-8");
                val stringWriter = StringWriter();
                tlt.merge(context, stringWriter);
                zipOutputStream.putNextEntry(ZipEntry(getFileName(template, it)));
                zipOutputStream.write(stringWriter.toString().toByteArray());
                stringWriter.close();
                zipOutputStream.closeEntry();
            }
        }
        zipOutputStream.close();
        return byteArrayOutputStream.toByteArray();
    }

    fun getCodeByEnum(enumVO: EnumVO): String {
        VelocityInitializer.initVelocity();
        val context = VelocityContext();
        context.put("enum", enumVO);
        val tlt = Velocity.getTemplate(enumTemplateList[0], "utf-8");
        val stringWriter = StringWriter();
        tlt.merge(context, stringWriter);
        stringWriter.close();
        return stringWriter.toString();
    }

    fun getPreviewCode(genVO: GenVO): Map<String, String> {
        VelocityInitializer.initVelocity();
        val context = VelocityContext();
        val code: MutableMap<String, String> = HashMap()
//        GenUtils.processImportList(genVO);
        templateList.forEach {
            context.put("gen", genVO);
            val tlt = Velocity.getTemplate(it, "utf-8");
            val stringWriter = StringWriter();
            tlt.merge(context, stringWriter);
            code[getName(it, genVO)] = stringWriter.toString();
            stringWriter.close();
        }
        return code;
    }
    fun getPreviewCode(genVOList: List<GenVO>): HashMap<String, ArrayList<Map<String, String>>>  {
        val codeMap:HashMap<String, ArrayList<Map<String, String>>> = hashMapOf();
        genVOList.forEach {
            val moduleMap =  codeMap[it.module]?: arrayListOf();
            moduleMap.run {
                add(getPreviewCode(it))
            }
            codeMap[it.module!!] = moduleMap;
        }
        return codeMap;
    }

    fun getZipEnumCode(enumVO: EnumVO, groupId: String): ByteArray {
        val byteArrayOutputStream = ByteArrayOutputStream();
        val zipOutputStream = ZipOutputStream(byteArrayOutputStream)
        VelocityInitializer.initVelocity()
        val context = VelocityContext()
        enumTemplateList.forEach { template ->
            context.put("enum", enumVO)
            val tlt = Velocity.getTemplate(template, "utf-8");
            val stringWriter = StringWriter();
            tlt.merge(context, stringWriter);
            zipOutputStream.putNextEntry(ZipEntry(getFileName(template, enumVO, groupId)));
            zipOutputStream.write(stringWriter.toString().toByteArray());
            stringWriter.close();
            zipOutputStream.closeEntry();
        }
        zipOutputStream.close();
        return byteArrayOutputStream.toByteArray();
    }

    fun getZipConfigCode(configVO: ConfigVO, groupId: String): ByteArray {
        val byteArrayOutputStream = ByteArrayOutputStream();
        val zipOutputStream = ZipOutputStream(byteArrayOutputStream)
        VelocityInitializer.initVelocity()
        val context = VelocityContext()
        configTemplate.forEach { template ->
            context.put("config", configVO)
            val tlt = Velocity.getTemplate(template, "utf-8");
            val stringWriter = StringWriter();
            tlt.merge(context, stringWriter);
            zipOutputStream.putNextEntry(ZipEntry(getFileName(template, configVO, groupId)));
            zipOutputStream.write(stringWriter.toString().toByteArray());
            stringWriter.close();
            zipOutputStream.closeEntry();
        }
        zipOutputStream.close();
        return byteArrayOutputStream.toByteArray();
    }

    fun getCodeByConfig(configVO: ConfigVO): String {
        VelocityInitializer.initVelocity();
        val context = VelocityContext();
        context.put("config", configVO);
        val tlt = Velocity.getTemplate(configTemplate[0], "utf-8");
        val stringWriter = StringWriter();
        tlt.merge(context, stringWriter);
        stringWriter.close();
        return stringWriter.toString();

    }
}


fun main() {
    VelocityInitializer.initVelocity()
    val context = VelocityContext()
    val genFieldList = arrayListOf<GenField>();
    genFieldList.add(GenField( tableField = "nick_name", isTime = false,fieldType= "String", name = "nickName", comment = "用户昵称", search = true, import = true, add = true, res = true, tableFieldType = "varchar", type = false, export = false));
    genFieldList.add(GenField(tableField = "phone", isTime = false, fieldType="String", name = "phone", comment = "手机号", search = true, import = true, add = true, res = true, tableFieldType = "varchar", type = false, export = true))
    genFieldList.add(GenField(tableField = "register_time", isTime = true, fieldType =  "LocalDateTime", name = "registerTime", comment = "注册时间", search = true, import = true, add = true, res = true, tableFieldType = "dateTime", type = false, export = true))
    genFieldList.add(GenField(tableField = "balance", isTime = false, fieldType = "BigDecimal", name = "balance", comment = "用户余额", search = true, import = true, add = true, res = true, tableFieldType = "decimal", type = false, export = true))
    genFieldList.add(GenField(tableField="user_status", isTime = false, fieldType="UserStatus", name = "userStatus", comment = "用户状态", search = true, import = true, add = true, res = true, tableFieldType = "smallint", type = true, export = true))
    val genVo: GenVO = GenVO(tableName = "base_user111", comment = "基本用户表", fieldList = genFieldList,
            className = "baseUser111", clazzName = "BaseUser111",
            packageName = "com.tang.service.account", module = "com.tang.portal",
            dateTime = "2023-4-3 09:04:00", api = "base/user",
            frontPath = "base/user")
    val codeList = VelocityUtils.getPreviewCode(arrayListOf(genVo))
    codeList.forEach{
        it.value.forEach {
            it.forEach { t, u ->
                println(t)
                println(u)
            }
        }
    }

//    GenUtils.processImportList(genVo);
//    context.put("gen", genVo)
//    val templateList = listOf(
////            "vm/java/model/req/ReqAdd.java.vm",
////            "vm/java/model/req/Req.java.vm",
////            "vm/java/model/res/Res.java.vm",
////            "vm/java/model/res/ResDetail.java.vm",
////            "vm/java/Controller-admin.java.vm",
//            "vm/java/Domain.java.vm",
////            "vm/java/Facade.java.vm",
////            "vm/java/IService.java.vm",
////            "vm/java/Mapper.java.vm",
////            "vm/java/ServiceImpl.java.vm",
////            "vm/react/config/columns.tsx.vm",
////            "vm/react/Tag.ts.vm",
////            "vm/react/index.tsx.vm",
////            "vm/react/type.ts.vm"
//    )
////    val zipOutputStream = ZipOutputStream(FileOutputStream("/Users/cool/Desktop/generate.zip"))
//    templateList.forEach {
//        val template = Velocity.getTemplate(it, "utf-8");
//        val stringWriter = StringWriter();
//        template.merge(context, stringWriter);
//        println(stringWriter.toString())
////        zipOutputStream.putNextEntry(ZipEntry(VelocityUtils.getFileName(it, genVo)));
////        zipOutputStream.write(stringWriter.toString().toByteArray());
////        stringWriter.close();
////        zipOutputStream.closeEntry();
//    }
////    zipOutputStream.close();

//    println(GenUtils.getClassName("base_user"))
//    println(GenUtils.getClazzName("base_user"))
//    println(GenUtils.getTag("base_user"))
}
